#ifndef ODBC_COLUMN_HPP
#define ODBC_COLUMN_HPP

namespace odbc
{

/// \ingroup odbcpp
/// \brief It implements a column that is used by data set returning statements for returning the results.
/// \param StatExecPolicyT the execution policy of the statement. The execution policy determines how the column is 
///		bound to the buffers and how the values for the current field are fetched.
/// \details
///		Since the column class is not dependent on the type of value contained in the field, there is a an idiom 
///		implemented that allows to use buffers specialized for a dedicated type, which is specified when the column is 
///		created.
template< class StatExecPolicyT>
class column
{
	/// \private
	/// \brief The base class, providing polymorphic interface for buffer binding and value fetching.
	class buffer_wrapper_base
	{
	public:
		/// \brief Dummy destructor.
		virtual ~buffer_wrapper_base() { }

		/// \brief It binds a buffer to the specified position in the specified statement.
		/// \param stat_handle the handle of the ODBC statement that needs to be prepared.
		/// \param position the position of the column.
		virtual void bind( SQLHANDLE stat_handle, int position) = 0;

		/// \brief It fetches the value in the column's buffer from the current record.
		/// \param stat_handle the statement being executed.
		/// \param position the position of the column.
		virtual boost::any fetch_value( SQLHANDLE stat_handle, int position) = 0;
	};

	/// \private
	/// \brief It specializes the buffer binding and value fetching for the specified type.
	/// \param T the type of the value that is expected to be fetched for this column.
	template< class T>
	class buffer_wrapper: public buffer_wrapper_base
	{
		typedef details::buffer<T> wrapped_buffer;
	public:
		/// \brief It initializes the wrapper.
		/// \param buffer the buffer that should be bind to the column.
		buffer_wrapper( const details::buffer<T>& buffer)
			: buffer_( buffer) { }

		/// \brief It gets the buffer bound to the column.
		/// \{
		const details::buffer<T>& buffer() const { return buffer_; }
		details::buffer<T>& buffer() { return buffer_; }
		/// \}

		/// \see buffer_wrapper_base::bind( SQLHANDLE, int)
		virtual void bind( SQLHANDLE stat_handle, int position)
		{
			StatExecPolicyT::bind_column( buffer_, stat_handle, static_cast< SQLUSMALLINT>( position));
		}

		/// \see buffer::wrapper_base::fetch_value( SQLHANDLE, int)
		virtual boost::any fetch_value( SQLHANDLE stat_handle, int position)
		{
			return StatExecPolicyT::fetch_column( buffer_, stat_handle, position);
		}

	private:
		/// \brief It contains the buffer to be bound to the column.
		details::buffer<T> buffer_;
	};

public:
	/// \brief It prepares the column.
	/// \param T the type of the value expected to be found in the column.
	/// \param stat_h the handle of the statement the column should be bound to.
	/// \param buffer the buffer to be bound for this column.
	/// \param position the position of the column in the dataset.
	template< typename T>
	column( SQLHANDLE stat_h, const details::buffer< T>& buffer, int position)
		: p_buf_wrapper_( new buffer_wrapper<T>( buffer))
		, position_( position)
		, stat_handle_( stat_h)
	{
		p_buf_wrapper_->bind( stat_handle_, position_);
	}


	/// \brief It destroys the bound buffer.
	~column()
	{
		delete p_buf_wrapper_;
	}

	/// \brief It fetches the value contained in the column for the current record. If the value is NULL, the returned 
	///		value is marked as empty.
	boost::any fetch()
	{
		return p_buf_wrapper_->fetch_value( stat_handle_, position_);
	}

private:
	/// \internal
	/// \brief The converted from static polymorphism to dynamic polymorphism.
	buffer_wrapper_base* p_buf_wrapper_;

	/// \internal
	/// \brief It contains the position of the column in the returned dataset. 
	int position_;

	/// \internal
	/// \brief The handle of the statement that uses this column.
	SQLHANDLE stat_handle_;

private:
	// Since copying parameter means rebinding it to the statement, don't allow copy
	column& operator=( const column&);
	column( const column&);

};


} // namespace odbc

#endif // ODBC_COLUMN_HPP
